/*****************************************************************
JADE - Java Agent DEvelopment Framework is a framework to develop 
multi-agent systems in compliance with the FIPA specifications.
Copyright (C) 2000 CSELT S.p.A. 

GNU Lesser General Public License

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, 
version 2.1 of the License. 

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA  02111-1307, USA.
 *****************************************************************/

package market;

import jade.core.Agent;
import jade.core.behaviours.*;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;

import java.util.*;
import java.lang.Math;
import java.lang.Integer;

public class WholesaleAgent extends Agent {
	// The catalogue of products for sale (maps the title of a product to its price)
	private Hashtable catalogue;
	// We consider only 1 product - beer
	private String title_of_product = "Beer";
	// Profit margin
	private Double profit_margin;
	// Original price
	private Double original_price;
	// Product adding cycle time
	private int cycle_time;
	// Number of products to add during a cycle
	private int cycle_number_of_products;

	// Put agent initializations here
	protected void setup() {
		System.out.println("Hallo! Wholesale-agent "+getAID().getName()+" is ready.");
		// Create the catalogue
		catalogue = new Hashtable();

		title_of_product = "Beer";
		original_price = 10.0;
		profit_margin = 0.20;
		cycle_time = 20000;//20sec
		cycle_number_of_products = 5;
		
		// Input arguments
		Object[] args = getArguments();
		if(args.length>0)
		{
			try {
				original_price = Double.parseDouble((String) args[0]);
			} catch (NumberFormatException e) {
				System.err.println("Argument must be an doubleeee");
				System.exit(1);
			}	
		}
		if(args.length>1)
		{
			try {
				profit_margin = Double.parseDouble((String) args[1]);
			} catch (NumberFormatException e) {
				System.err.println("Argument must be an doublee");
				System.exit(1);
			}	
		}
		if(args.length>2)
		{
			try {
				cycle_time = Integer.parseInt((String) args[2]);
			} catch (NumberFormatException e) {
				System.err.println("Argument must be an integer");
				System.exit(1);
			}	
		}
		if(args.length>3)
		{
			try {
				cycle_number_of_products = Integer.parseInt((String) args[3]);
			} catch (NumberFormatException e) {
				System.err.println("Argument must be an integer");
				System.exit(1);
			}	
		}
		
		
		// Register the product-selling service in the yellow pages
		DFAgentDescription dfd = new DFAgentDescription();
		dfd.setName(getAID());
		ServiceDescription sd = new ServiceDescription();
		sd.setType("product-selling-wholesale");
		sd.setName("SHOP-product-trading-wholesale");
		dfd.addServices(sd);
		try {
			DFService.register(this, dfd);
		}
		catch (FIPAException fe) {
			fe.printStackTrace();
		}

		// Add the behaviour serving queries from buyer agents
		addBehaviour(new OfferRequestsServer());

		// Add the behaviour serving purchase orders from buyer agents
		addBehaviour(new PurchaseOrdersServer());
		
		// Add a TickerBehaviour that adds products to wholesale
			addBehaviour(new TickerBehaviour(this, cycle_time) {
				protected void onTick() {
					catalogue.put(title_of_product, new Integer((int)Math.floor((original_price*profit_margin)+original_price)));
					System.out.println("[Wholesale:"+getAID().getName()+"] Adding "
					+cycle_number_of_products+" "+title_of_product +" to wholesale.");

				}
			} );
	}

	// Put agent clean-up operations here
	protected void takeDown() {
		// Deregister from the yellow pages
		try {
			DFService.deregister(this);
		}
		catch (FIPAException fe) {
			fe.printStackTrace();
		}
		// Printout a dismissal message
		System.out.println("Seller-wholesale-agent "+getAID().getName()+" terminating.");
	}

	/**
	   Inner class OfferRequestsServer.
	   This is the behaviour used by Product-seller agents to serve incoming requests 
	   for offer from buyer agents.
	   If the requested product is in the local catalogue the seller agent replies 
	   with a PROPOSE message specifying the price. Otherwise a REFUSE message is
	   sent back.
	 */
	private class OfferRequestsServer extends CyclicBehaviour {
		public void action() {
			MessageTemplate mt = MessageTemplate.MatchPerformative(ACLMessage.CFP);
			ACLMessage msg = myAgent.receive(mt);
			if (msg != null) {
				// CFP Message received. Process it
				String title = msg.getContent();
				ACLMessage reply = msg.createReply();

				Integer price = (Integer) catalogue.get(title);
				if (price != null) {
					// The requested product is available for sale. Reply with the price
					reply.setPerformative(ACLMessage.PROPOSE);
					reply.setContent(String.valueOf(price.intValue()));
				}
				else {
					// The requested product is NOT available for sale.
					reply.setPerformative(ACLMessage.REFUSE);
					reply.setContent("not-available");
				}
				myAgent.send(reply);
			}
			else {
				block();
			}
		}
	}  // End of inner class OfferRequestsServer

	/**
	   Inner class PurchaseOrdersServer.
	   This is the behaviour used by Product-seller agents to serve incoming 
	   offer acceptances (i.e. purchase orders) from buyer agents.
	   The seller agent removes the purchased product from its catalogue 
	   and replies with an INFORM message to notify the buyer that the
	   purchase has been sucesfully completed.
	 */
	private class PurchaseOrdersServer extends CyclicBehaviour {
		public void action() {
			MessageTemplate mt = MessageTemplate.MatchPerformative(ACLMessage.ACCEPT_PROPOSAL);
			ACLMessage msg = myAgent.receive(mt);
			if (msg != null) {
				// ACCEPT_PROPOSAL Message received. Process it
				String title = msg.getContent();
				ACLMessage reply = msg.createReply();

				Integer price = (Integer) catalogue.remove(title);
				if (price != null) {
					reply.setPerformative(ACLMessage.INFORM);
					System.out.println(title+" sold to agent "+msg.getSender().getName());
				}
				else {
					// The requested product has been sold to another buyer in the meanwhile .
					reply.setPerformative(ACLMessage.FAILURE);
					reply.setContent("not-available");
				}
				myAgent.send(reply);
			}
			else {
				block();
			}
		}
	}  // End of inner class OfferRequestsServer
}
